package ia;

import java.util.ArrayList;
import java.util.Collections;

public class Aestrella45 extends Aestrella {
    private ArrayList<Nodo45>  nAbiertos = new ArrayList<Nodo45>();
    private ArrayList<Nodo45>  nCerrados = new ArrayList<Nodo45>();
    private static Aestrella45 instancia = new Aestrella45();
    
    private Aestrella45(){}

    public static Aestrella45 getInstance(){
        return instancia;
    }

    public void propagaMejora(Nodo45 nodo){
        for(Nodo45 n: nodo.getHijos()){
            n.setCoste(nodo.getCoste()+n.getTransicionCoste());
            propagaMejora(n);
        }
    }

    @Override
    public float buscar() {
        boolean salir = false;
        float coste = 0;
    	
        int[] posAbdel  = general.getPosAbdel();
        int[] posGertru = general.getPosGertru();
        int iteracion   = 1;
        int cont        = 1;
        int[][] matrizPeligrosidades = general.getMatriz();
        
        ArrayList<Nodo45> nSucesores = new ArrayList<Nodo45>();
        ArrayList<Nodo45> recorrido  = new ArrayList<Nodo45>();

        Nodo45 nInicial = new Nodo45(posAbdel[0],posAbdel[1],Orientacion.N);

        nAbiertos.add(nInicial);
        nInicial.setVHeuristica(heuristica.calculaHeuristica(nInicial, posGertru));
        nCerrados.clear();
        
        while(!salir){
            if (nAbiertos.isEmpty()) 
            	          System.out.println("Lista de nodos abiertos vacia");                       

            Nodo45 mejorNodo = Collections.min(nAbiertos);

            System.out.println("Iteración "+iteracion+":");
            System.out.println("Candidatos:              "+ nAbiertos);
            System.out.println("Mejor Nodo:              "+ mejorNodo);
            nAbiertos.remove(mejorNodo);
            
            if(meta(mejorNodo)) {               
                coste = mejorNodo.getCoste();                
                System.out.println("\nFin: el nodo encontrado es meta");
                mejorNodo.mostrarResultado( nCerrados);
                System.out.println();
                
                salir= true;
                break;
            }
            nCerrados.add(mejorNodo);

            nSucesores = mejorNodo.aplicaOperadores(matrizPeligrosidades);

            for(Nodo45 i:nSucesores){
                i.setId(cont);
                cont++;
                i.setVHeuristica(heuristica.calculaHeuristica(i, posGertru));
            }
            recorrido.addAll(mejorNodo.getAntecesores());
            Collections.reverse(recorrido);
            recorrido.add(mejorNodo);
            System.out.println("Recorrido seguido:       " + recorrido);
            recorrido.clear();
            System.out.println("Descendientes:           " + nSucesores+"\n\n");

            iteracion++;
            ArrayList<Nodo45> aux = new ArrayList<Nodo45>();
            aux.addAll(nSucesores);

            for(Nodo45 s:nSucesores){         
                s.setPadre(mejorNodo);

                if(nAbiertos.contains(s)){
                    Nodo45 viejo = nAbiertos.get(nAbiertos.indexOf(s));
                    if(viejo.getCoste()>s.getCoste()) {
                        viejo.setPadre(mejorNodo);
                        s.setId(cont);
                        cont++;
                        viejo.setCoste(s.getCoste());
                        viejo.setVHeuristica(heuristica.calculaHeuristica(viejo, posGertru));
                    }
                    aux.remove(s);
                    aux.add(viejo);
                }
                if( nCerrados.contains(s)){
                    Nodo45 viejo =  nCerrados.get( nCerrados.indexOf(s));                    
                    if(viejo.getCoste()>s.getCoste()){
                        viejo.setPadre(mejorNodo);
                        s.setId(cont);
                        cont++;
                        viejo.setCoste(s.getCoste());
                        viejo.setVHeuristica(heuristica.calculaHeuristica(viejo, posGertru));
                    }
                    aux.remove(s);
                    aux.add(viejo);
                    propagaMejora(viejo);
                }
                if(!nAbiertos.contains(s)&! nCerrados.contains(s)){
                    s.setVHeuristica(heuristica.calculaHeuristica(s, posGertru));
                    nAbiertos.add(s);
                    aux.add(s);
                }
            }
            nSucesores.clear();
            nSucesores.addAll(aux);
            aux.clear();
        }
        
    nAbiertos.clear();
    nCerrados.clear();
    nSucesores.clear();

    return coste;
    }
}